<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>履程AI小助手</title>

    <!-- Tailwind CSS -->
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"/>

    <!-- 内联样式优化：仅保留必要样式 -->
    <style>
        .typing-cursor::after {
            content: "|";
            animation: blink 1s step-end infinite;
        }

        @keyframes blink {
            from, to {
                opacity: 1
            }
            50% {
                opacity: 0
            }
        }

        body {
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
        }

        /* 滚动条样式 */
        ::-webkit-scrollbar {
            width: 6px;
        }

        ::-webkit-scrollbar-track {
            background: #f1f1f1;
        }

        ::-webkit-scrollbar-thumb {
            background: #c1c1c1;
            border-radius: 3px;
        }

        ::-webkit-scrollbar-thumb:hover {
            background: #a8a8a8;
        }

        /* 输入框自适应高度 */
        textarea {
            min-height: 44px;
            max-height: 200px;
            transition: height 0.2s;
        }

        /* 动画样式 */
        @keyframes pulse {
            0%, 100% {
                opacity: .5
            }
            50% {
                opacity: 1
            }
        }

        .animate-pulse {
            animation: pulse 1.5s infinite;
        }

        .typing-cursor::after {
            content: "|";
            animation: blink 1s step-end infinite;
        }

        @keyframes blink {
            from, to {
                opacity: 1
            }
            50% {
                opacity: 0
            }
        }
    </style>
</head>
<body>
<div id="app" class="flex flex-col h-screen bg-gray-50">
    <!-- 顶部导航栏 -->
    <header class="bg-white shadow-sm py-3 px-4 flex items-center justify-between">
        <div class="flex items-center">
            <div class="text-xl font-bold text-blue-600">履程AI小助手</div>
        </div>
        <div class="flex items-center space-x-3">
            <!-- 新建会话按钮（SVG） -->
            <button
                    @click="startNewConversation"
                    class="ml-2 p-3 rounded-lg bg-green-500 hover:bg-green-600 text-white"
                    style="width: 50px"
            >
                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
                     class="h-5 w-5 mx-auto">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
                </svg>
            </button>

            <!-- 切换暗黑模式（SVG） -->
            <button @click="toggleDarkMode" class="p-2 rounded-full hover:bg-gray-100">
                <svg v-if="darkMode" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
                     stroke="currentColor" class="h-5 w-5 text-yellow-300">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                          d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/>
                </svg>
                <svg v-else xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
                     class="h-5 w-5 text-blue-500">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                          d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/>
                </svg>
            </button>
        </div>
    </header>

    <!-- 聊天内容区域 -->
    <main class="flex-1 overflow-y-auto p-4 space-y-6"
          ref="chatContainer"
          :class="{ 'bg-gray-800': darkMode }">
        <div v-for="(message, index) in messages" :key="index" class="max-w-3xl mx-auto">
            <div :class="['flex', message.role === 'user' ? 'justify-end' : 'justify-start']">
                <div
                        :class="[
              'flex items-start space-x-3',
              message.role === 'user' ? 'flex-row-reverse space-x-reverse' : ''
            ]"
                >
                    <div
                            :class="[
                'w-8 h-8 rounded-full flex items-center justify-center',
                message.role === 'user'
                  ? 'bg-blue-100 text-blue-600'
                  : 'bg-green-100 text-green-600',
                darkMode && message.role === 'assistant' ? 'bg-gray-700 text-green-400' : ''
              ]"
                    >
                        <svg v-if="message.role === 'user'" xmlns="http://www.w3.org/2000/svg" fill="none"
                             viewBox="0 0 24 24" stroke="currentColor" class="w-5 h-5">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                                  d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
                        </svg>
                        <svg v-else xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
                             stroke="currentColor" class="w-5 h-5">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                                  d="M9.663 17h4.673M12 3v1m6.364 16.708l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0zm0 0v4m0 0l2 2m-2-2l-2 2"/>
                        </svg>
                    </div>
                    <div
                            :class="[
                'p-3 rounded-lg max-w-lg',
                message.role === 'user'
                  ? 'bg-blue-500 text-white'
                  : darkMode
                  ? 'bg-gray-700 text-gray-100 border border-gray-600'
                  : 'bg-white shadow border border-gray-100'
              ]"
                    >
                        <div v-else class="whitespace-pre-wrap">
    <span
            v-for="(char, charIndex) in message.content"
            :key="charIndex"
            :class="{
            'opacity-0': charIndex >= message.visibleChars,
            'fade-in': charIndex < message.visibleChars
        }"
    >{{ char }}</span>
                            <span v-if="message.isStreaming" class="typing-cursor"></span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </main>

    <!-- 输入框区域 -->
    <footer :class="['border-t p-4', darkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200']">
        <div class="max-w-3xl mx-auto relative">
            <div class="flex items-center">
          <textarea
                  v-model="userInput"
                  @keydown.enter.exact.prevent="sendMessage"
                  @keydown.ctrl.enter.exact.prevent="() => { userInput.value += '\n' }"
                  @keydown.esc.exact="stopResponse"
                  placeholder="输入您的问题..."
                  :class="[
              'flex-1 border rounded-lg py-3 px-4 pr-12 focus:outline-none focus:ring-2 resize-none',
              darkMode
                ? 'bg-gray-700 border-gray-600 text-white focus:ring-blue-400 placeholder-gray-400'
                : 'border-gray-300 focus:ring-blue-500 focus:border-transparent'
            ]"
                  rows="1"
                  ref="textarea"
                  @input="adjustTextareaHeight"
          ></textarea>
                <button
                        @click="isLoading ? stopResponse() : sendMessage()"
                        :disabled="!isValidMessage() && !isLoading"
                        :class="[
              'ml-2 p-3 rounded-lg',
              isLoading
                ? 'bg-red-500 hover:bg-red-600 text-white'
                : 'bg-blue-500 hover:bg-blue-600 text-white',
              'disabled:opacity-50 disabled:cursor-not-allowed'
            ]"
                >
                    <svg v-if="!isLoading" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
                         stroke="currentColor" class="w-5 h-5">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                              d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/>
                    </svg>
                    <svg v-else xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
                         class="w-5 h-5">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4"/>
                    </svg>
                </button>
            </div>
        </div>
    </footer>
</div>

<!-- Vue 入口脚本 -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.prod.min.js"></script>
<script>
    const {createApp, ref, nextTick, onMounted, watch} = Vue;

    createApp({
        setup() {
            const messages = ref([]);
            const userInput = ref('');
            const isLoading = ref(false);
            const chatContainer = ref(null);
            const textarea = ref(null);
            const darkMode = ref(false);

            const memoryId = ref(Date.now().toString());
            let controller = null;
            let typingInterval = null;

            // 调整输入框高度
            const adjustTextareaHeight = () => {
                const el = textarea.value;
                el.style.height = 'auto';
                el.style.height = `${Math.max(44, Math.min(el.scrollHeight, 200))}px`;
            };

            // 滚动到底部
            const scrollToBottom = () => {
                nextTick(() => {
                    if (chatContainer.value) {
                        chatContainer.value.scrollTop = chatContainer.value.scrollHeight;
                    }
                });
            };

            // 切换暗黑模式
            const toggleDarkMode = () => {
                darkMode.value = !darkMode.value;
                localStorage.setItem('darkMode', darkMode.value);
            };

            // 新建会话
            const startNewConversation = () => {
                messages.value = [];
                memoryId.value = Date.now().toString();
                messages.value.push({
                    role: 'assistant',
                    content: '你好！我是你是履程开发团队开发的AI智能查询助手，请问有什么能帮到您？',
                    visibleChars: 0
                });
                setTimeout(() => {
                    messages.value[0].visibleChars = messages.value[0].content.length;
                }, 100);
                scrollToBottom();
                nextTick(() => textarea.value.focus());
            };

            // 打字效果
            const startTypingEffect = (messageIndex) => {
                const message = messages.value[messageIndex];
                if (!message || message.visibleChars >= message.content.length) {
                    clearInterval(typingInterval);
                    typingInterval = null;
                    return;
                }
                message.visibleChars++;
                scrollToBottom();
            };

            const sendMessage = async () => {
                if (!/\S/.test(userInput.value) || isLoading.value) return;

                // 清除旧请求
                if (controller) controller.abort();
                controller = new AbortController();

                const userMsg = {
                    role: 'user',
                    content: userInput.value.trim(),
                    visibleChars: userInput.value.trim().length
                };
                messages.value.push(userMsg);

                const assistantMsg = {
                    role: 'assistant',
                    content: '',
                    visibleChars: 0,
                    isStreaming: true
                };
                messages.value.push(assistantMsg);
                const idx = messages.value.length - 1;

                userInput.value = '';
                adjustTextareaHeight();
                scrollToBottom();
                isLoading.value = true;

                try {
                    const res = await fetch(`/chat?message=${encodeURIComponent(userMsg.content)}&memoryId=${memoryId.value}`, {
                        signal: controller.signal
                    });

                    if (!res.ok) throw new Error(`HTTP 错误! 状态码: ${res.status}`);

                    const reader = res.body.getReader();
                    const decoder = new TextDecoder();
                    let buffer = '';

                    while (true) {
                        const {done, value} = await reader.read();

                        if (done) {
                            // 流结束
                            messages.value[idx].isStreaming = false;
                            isLoading.value = false;
                            break;
                        }

                        buffer += decoder.decode(value, {stream: true});
                        messages.value[idx].content = buffer;
                        messages.value[idx].visibleChars = buffer.length;
                        scrollToBottom();
                    }
                } catch (e) {
                    console.error('请求错误:', e);
                    messages.value[idx].content = '抱歉，出现错误: ' + e.message;
                    messages.value[idx].visibleChars = messages.value[idx].content.length;
                    messages.value[idx].isStreaming = false;
                    isLoading.value = false;
                }
            };


            // 停止响应
            const stopResponse = () => {
                if (controller) controller.abort();
                isLoading.value = false;
                if (typingInterval) clearInterval(typingInterval);
            };

            // 验证是否为有效输入
            const isValidMessage = () => /\S/.test(userInput.value);

            // 页面初始化
            onMounted(() => {
                darkMode.value =
                    localStorage.getItem('darkMode') === 'true' ||
                    (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);

                if (!messages.value.some(msg => msg.isWelcome)) {
                    messages.value.push({
                        role: 'assistant',
                        content: '你好！我是你是履程开发团队开发的AI智能查询助手，请问有什么能帮到您？',
                        isWelcome: true,
                        visibleChars: 0
                    });
                    setTimeout(() => {
                        messages.value[0].visibleChars = messages.value[0].content.length;
                    }, 100);
                }

                nextTick(() => textarea.value?.focus());
                window.visualViewport?.addEventListener('resize', () => {
                    if (document.activeElement === textarea.value) {
                        scrollToBottom();
                    }
                });
            });

            // 监听消息变化并滚动到底部
            watch(messages, scrollToBottom, {deep: true});

            return {
                messages,
                userInput,
                isLoading,
                darkMode,
                chatContainer,
                textarea,
                sendMessage,
                stopResponse,
                toggleDarkMode,
                adjustTextareaHeight,
                startNewConversation,
                isValidMessage
            };
        }
    }).mount('#app');
</script>
</body>
</html>
